home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DDJMAG / DDJ9110.ZIP / 386BSD.101 next >
Text File  |  1991-09-10  |  12KB  |  425 lines

  1. _PORTING UNIX TO THE 386: MULTIPROGRAMMING AND MULTITASKING_
  2. by William Frederick Jolitz and Lynne Greer Jolitz
  3.  
  4. [LISTING ONE]
  5.  
  6. /* code fragment from i386/trap.c (in trap() and syscall()) */
  7.  ...
  8.     if (want_resched) {
  9.         /*
  10.          * Enqueue our current running process first, so
  11.          * that we may eventually run again. Block clock
  12.          * interrupts that may interfere with priority
  13.          * (e.g. we'd rather it not be recalculated part
  14.          * way thru setrun).
  15.          */
  16.         (void) splclock();
  17.         setrq(p);
  18.         (void) splnone();
  19.         p->p_stats->p_ru.ru_nivcsw++;
  20.         swtch();
  21.         while (i = CURSIG(p))
  22.             psig(i);
  23.     }
  24.  ...
  25.  
  26.  
  27.  
  28.  
  29. [LISTING TWO]
  30.  
  31. /*-
  32.  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
  33.  * Copyright (c) 1991 The Regents of the University of California.
  34.  * All rights reserved.
  35.  */
  36.  
  37. /*
  38.  * General sleep call.
  39.  * Suspends current process until a wakeup is made on chan.
  40.  * The process will then be made runnable with priority pri.
  41.  * Sleeps at most timo/hz seconds (0 means no timeout).
  42.  * If pri includes PCATCH flag, signals are checked
  43.  * before and after sleeping, else signals are not checked.
  44.  * Returns 0 if awakened, EWOULDBLOCK if the timeout expires.
  45.  * If PCATCH is set and a signal needs to be delivered,
  46.  * ERESTART is returned if the current system call should be restarted
  47.  * if possible, and EINTR is returned if the system call should
  48.  * be interrupted by the signal (return EINTR).
  49.  */
  50. tsleep(chan, pri, wmesg, timo)
  51.     caddr_t chan;
  52.     int pri;
  53.     char *wmesg;
  54.     int timo;
  55. {
  56.     register struct proc *p = curproc;
  57.     register struct slpque *qp;
  58.     register s;
  59.     int sig, catch = pri & PCATCH;
  60.     extern int cold;
  61.     int endtsleep();
  62.  
  63.     s = splhigh();
  64.     if (cold || panicstr) {
  65.         /*
  66.          * After a panic, or during autoconfiguration,
  67.          * just give interrupts a chance, then just return;
  68.          * don't run any other procs or panic below,
  69.          * in case this is the idle process and already asleep.
  70.          */
  71.         splx(safepri);
  72.         splx(s);
  73.         return (0);
  74.     }
  75.  
  76. #ifdef DIAGNOSTIC
  77.     if (chan == 0 || p->p_stat != SRUN || p->p_rlink)
  78.         panic("tsleep");
  79. #endif
  80.  
  81.     p->p_wchan = chan;
  82.     p->p_wmesg = wmesg;
  83.     p->p_slptime = 0;
  84.     p->p_pri = pri & PRIMASK;
  85.  
  86.     /* Insert onto the tail of a sleep queue list. */
  87.     qp = &slpque[HASH(chan)];
  88.     if (qp->sq_head == 0)
  89.         qp->sq_head = p;
  90.     else
  91.         *qp->sq_tailp = p;
  92.     *(qp->sq_tailp = &p->p_link) = 0;
  93.  
  94.     /*
  95.      * If time limit to sleep, schedule a timeout
  96.      */
  97.     if (timo)
  98.         timeout(endtsleep, (caddr_t)p, timo);
  99.  
  100.     /* We put ourselves on the sleep queue and start our timeout
  101.      * before calling CURSIG, as we could stop there, and a wakeup
  102.      * or a SIGCONT (or both) could occur while we were stopped.
  103.      * A SIGCONT would cause us to be marked as SSLEEP
  104.      * without resuming us, thus we must be ready for sleep
  105.      * when CURSIG is called.  If the wakeup happens while we're
  106.      * stopped, p->p_wchan will be 0 upon return from CURSIG.
  107.      */
  108.     if (catch) {
  109.         p->p_flag |= SSINTR;
  110.         if (sig = CURSIG(p)) {
  111.             if (p->p_wchan)
  112.                 unsleep(p);
  113.             p->p_stat = SRUN;
  114.             goto resume;
  115.         }
  116.         if (p->p_wchan == 0) {
  117.             catch = 0;
  118.             goto resume;
  119.         }
  120.     }
  121.  
  122.     /* Set process sleeping, go find another process to run */
  123.     p->p_stat = SSLEEP;
  124.     p->p_stats->p_ru.ru_nvcsw++;
  125.     swtch();
  126.  
  127. resume:
  128.     splx(s);
  129.     p->p_flag &= ~SSINTR;
  130.  
  131.     /* cleanup timeout case */
  132.     if (p->p_flag & STIMO) {
  133.         p->p_flag &= ~STIMO;
  134.         if (catch == 0 || sig == 0)
  135.             return (EWOULDBLOCK);
  136.     } else if (timo)
  137.         untimeout(endtsleep, (caddr_t)p);
  138.  
  139.     /* if signal was caught, return appropriately */
  140.     if (catch && (sig != 0 || (sig = CURSIG(p)))) {
  141.         if (p->p_sigacts->ps_sigintr & sigmask(sig))
  142.             return (EINTR);
  143.         return (ERESTART);
  144.     }
  145.     return (0);
  146. }
  147.  
  148.  
  149.  
  150.  
  151.  
  152. [LISTING THREE]
  153.  
  154. /*-
  155.  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
  156.  * Copyright (c) 1991 The Regents of the University of California.
  157.  * All rights reserved.
  158.  */
  159.  
  160. /* Wakeup on "chan"; set all processes
  161.  * sleeping on chan to run state.
  162.  */
  163. wakeup(chan)
  164.     register caddr_t chan;
  165. {
  166.     register struct slpque *qp;
  167.     register struct proc *p, **q;
  168.     int s;
  169.  
  170.     s = splhigh();
  171.     qp = &slpque[HASH(chan)];
  172.  
  173. restart:
  174.     for (q = &qp->sq_head; p = *q; ) {
  175. #ifdef DIAGNOSTIC
  176.         if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
  177.             panic("wakeup");
  178. #endif
  179.         if (p->p_wchan == chan) {
  180.             p->p_wchan = 0;
  181.             *q = p->p_link;
  182.             if (qp->sq_tailp == &p->p_link)
  183.                 qp->sq_tailp = q;
  184.             if (p->p_stat == SSLEEP) {
  185.                 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */
  186.                 if (p->p_slptime > 1)
  187.                     updatepri(p);
  188.                 p->p_slptime = 0;
  189.                 p->p_stat = SRUN;
  190.                 if (p->p_flag & SLOAD)
  191.                     setrq(p);
  192.                 /*
  193.                  * Since curpri is a usrpri,
  194.                  * p->p_pri is always better than curpri.
  195.                  */
  196.                 if ((p->p_flag&SLOAD) == 0)
  197.                     wakeup((caddr_t)&proc0);
  198.                 else
  199.                     need_resched();
  200.                 /* END INLINE EXPANSION */
  201.                 goto restart;
  202.             }
  203.         } else
  204.             q = &p->p_link;
  205.     }
  206.     splx(s);
  207. }
  208.  
  209.  
  210.  
  211. [LISTING FOUR]
  212.  
  213. /* Copyright (c) 1989, 1990, 1991 William Jolitz. All rights reserved.
  214.  * Written by William Jolitz 6/89
  215.  *
  216.  * Redistribution and use in source and binary forms are freely permitted
  217.  * provided that the above copyright notice and attribution and date of work
  218.  * and this paragraph are duplicated in all such forms.
  219.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  220.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  221.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  222.  */
  223.  
  224. /* Swtch() */
  225. ENTRY(swtch)
  226.  
  227.     incl    _cnt+V_SWTCH
  228.  
  229.     /* switch to new process. first, save context as needed */
  230.     movl    _curproc, %ecx
  231.     movl    P_ADDR(%ecx), %ecx
  232.  
  233.     /* unload processor registers, we need to use them */
  234.     movl    (%esp),%eax
  235.     movl    %eax, PCB_EIP(%ecx)
  236.     movl    %ebx, PCB_EBX(%ecx)
  237.     movl    %esp, PCB_ESP(%ecx)
  238.     movl    %ebp, PCB_EBP(%ecx)
  239.     movl    %esi, PCB_ESI(%ecx)
  240.     movl    %edi, PCB_EDI(%ecx)
  241.  
  242.     /* save system related details */
  243.     movl    $0,_CMAP2       /* blast temporary map PTE */
  244.     movw    _cpl, %ax
  245.     movw    %ax, PCB_IML(%ecx)  /* save ipl */
  246.  
  247.     /* save is done, now choose a new process or idle */
  248. rescanfromidle:
  249.     movl    _whichqs,%edi
  250. 2:
  251.     bsfl    %edi,%eax       /* found a full queue? */
  252.     jz  idle            /* if nothing, idle waiting for some */
  253.  
  254.     /* we have a queue with something in it */
  255.     btrl    %eax,%edi       /* clear queue full status */
  256.     jnb 2b          /* if it was clear, look for another */
  257.     movl    %eax,%ebx       /* save which one we are using */
  258.  
  259.     /* obtain the run queue header */
  260.     shll    $3,%eax
  261.     addl    $_qs,%eax
  262.     movl    %eax,%esi
  263.  
  264. #ifdef  DIAGNOSTIC
  265.       /* queue was promised to have a process in it */
  266.       cmpl  P_LINK(%eax),%eax   /* linked to self? (e.g. not on list) */
  267.       fje   panicswtch          /* not possible */
  268. #endif
  269.  
  270.     /* unlink from front of process q */
  271.     movl    P_LINK(%eax),%ecx
  272.     movl    P_LINK(%ecx),%edx
  273.     movl    %edx,P_LINK(%eax)
  274.     movl    P_RLINK(%ecx),%eax
  275.     movl    %eax,P_RLINK(%edx)
  276.  
  277.     /* is the queue truely empty? */
  278.     cmpl    P_LINK(%ecx),%esi
  279.     je  3f
  280.     btsl    %ebx,%edi       /* nope, set to indicate full */
  281. 3:
  282.     movl    %edi,_whichqs       /* update queue status */
  283.  
  284.     /* notify system we've rescheduled */
  285.     movl    $0,%eax
  286.     movl    %eax,_want_resched
  287.  
  288. #ifdef  DIAGNOSTIC
  289.     /* process was insured to be runnable, not sleeping */
  290.     cmpl    %eax,P_WCHAN(%ecx)
  291.     jne panicswtch
  292.     cmpb    $ SRUN,P_STAT(%ecx)
  293.     jne panicswtch
  294. #endif
  295.  
  296.     /* isolate process from run queues */
  297.     movl    %eax,P_RLINK(%ecx)
  298.  
  299.     /* record details of newproc in our global variables */
  300.     movl    %ecx,_curproc
  301.     movl    P_ADDR(%ecx),%edx
  302.     movl    %edx,_curpcb
  303.     movl    PCB_CR3(%edx),%ebx
  304.  
  305.     /* switch address space */
  306.     movl    %ebx,%cr3
  307.  
  308.     /* restore context */
  309.     movl    PCB_EBX(%edx), %ebx
  310.     movl    PCB_ESP(%edx), %esp
  311.     movl    PCB_EBP(%edx), %ebp
  312.     movl    PCB_ESI(%edx), %esi
  313.     movl    PCB_EDI(%edx), %edi
  314.     movl    PCB_EIP(%edx), %eax
  315.     movl    %eax, (%esp)
  316.  
  317. #ifdef  NPX
  318.     /* npx will interrupt next instruction, delay npx switch till then */
  319. #define CR0_TS  0x08
  320.     movl    %cr0,%eax
  321.     orb     $CR0_TS,%al         /* disable it */
  322.     movl    %eax,%cr0
  323. #endif
  324.  
  325.     /* set priority level we were at last time */
  326.     pushl   PCB_IML(%edx)
  327.     call    _splx
  328.     popl    %eax
  329.  
  330.     movl    %edx,%eax       /* return (1); (actually, non-zero) */
  331.     ret
  332.  
  333. /* When no processes are on the runq, Swtch branches to idle
  334.  * to wait for something to come ready.
  335.  */
  336.     .globl  Idle
  337. Idle:
  338. idle:
  339.     call    _spl0
  340.     cmpl    $0,_whichqs
  341.     jne rescanfromidle
  342.     hlt             /* wait for interrupt */
  343.     jmp idle
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350. [LISTING FIVE]
  351.  
  352. /* Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
  353.  * Written by William Jolitz 7/91
  354.  * Redistribution and use in source and binary forms are freely permitted
  355.  * provided that the above copyright notice and attribution and date of work
  356.  * and this paragraph are duplicated in all such forms.
  357.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  358.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  359.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  360.  */
  361.  
  362. /*
  363.  * Enqueue a process on a run queue. Process will be on a run queue
  364.  * until run for a time slice (swtch()), or removed by remrq().
  365.  * Should only be called with a running process, and with the
  366.  * processor protecting against rescheduling.
  367.  */
  368. setrq(p) struct proc *p; {
  369.     register rqidx;
  370.     struct prochd *ph;
  371.     struct proc *or;
  372.  
  373.     /* Rescale 256 priority levels to fit into 32 queue headers */
  374.     rqidx = p->p_pri / 4;
  375.  
  376. #ifdef  DIAGNOSTIC
  377.     /* If this process is already linked on run queue, we're in trouble. */
  378.     if (p->p_rlink != 0)
  379.         panic("setrq: already linked");
  380. #endif
  381.  
  382.     /* Link this process on the appropriate queue tail */
  383.     ph = qs + rqidx;
  384.     p->p_link = (struct proc *)ph;
  385.     or = p->p_rlink = ph->ph_rlink;
  386.     ph->ph_rlink = or->p_link = p;
  387.  
  388.     /* Indicate that this queue has at least one process in it */
  389.     whichqs |= (1<<rqidx);
  390. }
  391.  
  392. /* Dequeue a process from the run queue its stuck on. Must be called
  393.  * with rescheduling clock blocked.
  394.  */
  395. remrq(p) struct proc *p; {
  396.     register rqidx;
  397.     struct prochd *ph;
  398.  
  399.     /* Rescale 256 priority levels to fit into 32 queue headers */
  400.     rqidx = p->p_pri / 4;
  401.  
  402. #ifdef  DIAGNOSTIC
  403.     /* If a run queue is empty, something is definitely wrong */
  404.     if (whichqs & (1<<rqidx) == 0)
  405.         panic("remrq");
  406. #endif
  407.  
  408.     /* Unlink process off doublely-linked run queue */
  409.     p->p_link->p_rlink = p->p_rlink;
  410.     p->p_rlink->p_link = p->p_link;
  411.  
  412.     /* If something is still present on the queue,
  413.      * set the corresponding bit. Otherwise clear it.
  414.      */
  415.     ph = qs + rqidx;
  416.     if (ph->ph_link == ph)
  417.         whichqs &= ~(1<<rqidx);
  418.     else
  419.         whichqs |= (1<<rqidx);
  420.  
  421.     /* Mark this process as unlinked */
  422.     p->p_rlink = (struct proc *) 0;
  423. }
  424.  
  425.